package com.lfy.modules.safety.statistics.uv;

import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.lfy.domain.anno.Describe;
import com.lfy.modules.safety.domain.BlogPvStatistics;
import com.lfy.modules.safety.domain.BlogUvStatistics;
import com.lfy.modules.safety.mapper.BlogUvStatisticsMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.time.LocalDate;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.LongAdder;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author lvfeiyang
 */
@Describe("uv持久化任务")
@Slf4j
public class UvCache implements Job {
    private static final BlogUvStatisticsMapper BLOG_UV_STATISTICS_MAPPER;

    private static final Cache<String, CopyOnWriteArraySet<String>> UV_CACHE = Caffeine.newBuilder()
            .initialCapacity(16)
            .expireAfterWrite(2, TimeUnit.DAYS)
            .maximumSize(10_000)
            .build();

    static {
        BLOG_UV_STATISTICS_MAPPER = SpringUtil.getBean(BlogUvStatisticsMapper.class);
    }

    public static void put(String key) {
        if(StringUtils.isBlank(key)){
            return;
        }

        Optional.ofNullable(UV_CACHE.get(LocalDate.now().toString(), (v) -> new CopyOnWriteArraySet<String>())).ifPresent(v ->v.add(key));

    }


    public static BlogUvStatistics getNowDayUv() {
        LocalDate now = LocalDate.now();
        BlogUvStatistics blogUvStatistics = new BlogUvStatistics();
        CopyOnWriteArraySet<String> set = UV_CACHE.getIfPresent(now.toString());
        if (set == null) {
            blogUvStatistics.setNum(0L);
        } else {
            blogUvStatistics.setNum((long) set.size());
        }
        blogUvStatistics.setCreateTime(now.toString());
        return blogUvStatistics;
    }

    public static List<BlogUvStatistics> getSevenDaysUv() {
        BlogUvStatistics nowDayUv = getNowDayUv();
        List<BlogUvStatistics> blogUvStatistics = BLOG_UV_STATISTICS_MAPPER.selectList(new LambdaQueryWrapper<BlogUvStatistics>()
                .between(BlogUvStatistics::getCreateTime, LocalDate.now().minusDays(7), LocalDate.now().minusDays(1)));
        blogUvStatistics.add(nowDayUv);
        List<BlogUvStatistics> result = buidResult();
        for (BlogUvStatistics uvStatistics : result) {
            for (BlogUvStatistics blogUvStatistic : blogUvStatistics) {
                if (uvStatistics.getCreateTime().equals(blogUvStatistic.getCreateTime())) {
                    uvStatistics.setNum(blogUvStatistic.getNum());
                }
            }
        }
        return result;
    }
    private static List<BlogUvStatistics> buidResult(){

        return Stream.iterate(0, i -> ++i).limit(7).map(item -> {
            BlogUvStatistics blogUvStatistics = new BlogUvStatistics();
            blogUvStatistics.setNum(0L);
            blogUvStatistics.setCreateTime(LocalDate.now().minusDays(item).toString());
            return blogUvStatistics;
        }).sorted((Comparator.comparing(BlogUvStatistics::getCreateTime))).collect(Collectors.toList());
    }


    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        BlogUvStatistics blogUvStatistics = getNowDayUv();

        boolean flag = false;
        try{
            BLOG_UV_STATISTICS_MAPPER.insert(blogUvStatistics);
            flag = true;
        }catch (Exception e){
            log.error("uv统计数据插入失败");
        }
        //防止调度器重启立即执行一次，导致数据重复插入
        if(!flag){
            try {
                BLOG_UV_STATISTICS_MAPPER.update(blogUvStatistics,new LambdaQueryWrapper<BlogUvStatistics>().eq(BlogUvStatistics::getCreateTime,blogUvStatistics.getCreateTime()));
            }catch (Exception e){
                log.error("uv统计数据更新失败");
            }

        }
    }
}
